﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;

namespace BlackStar
{
    public enum DockStyle : int
    {
        None = 0,
        Top = 1,
        Bottom = 2,
        Left = 3,
        Right = 4,
        Fill = 5
    }

    /// <summary>
    /// Reads Components from compiled content.
    /// </summary>
    public class ComponentContentReader : ContentTypeReader<Component>
    {
        protected override Component Read(ContentReader input, Component existingInstance)
        {
            Component result = new Component();
            result.ReadContent(input);
            return result;
        }
    }

    /// <summary>
    /// the base object that all GUI items descend from.
    /// </summary>
    public class Component : IComparable<Component>
    {
        #region Events
        public event ComponentMouseEvent MouseEnter;
        public event ComponentMouseEvent MouseExit;
        public event ComponentMouseEvent MouseUp;
        public event ComponentMouseEvent MouseDown;
        public event ComponentMouseEvent MouseClick;
        public event ComponentMouseEvent MouseDoubleClick;
        
        public event ComponentEvent TextChanged;
        public event ComponentEvent Resized;
        public event ComponentEvent Enter;
        public event ComponentEvent Leave;

        public event ComponentKeyEvent KeyDown;
        public event ComponentKeyEvent KeyUp;

        #endregion

        #region Protected Variables
        protected string myText = "";
        protected string myFont = "Default";
        protected Color myFontColor = Color.Black;
        protected DockStyle myDock = DockStyle.None;
        protected bool myCanFocus = true;
        
        protected string myTabNext = string.Empty;
        protected string myTabPrev = string.Empty;

        protected Rectangle myDockSpace = Rectangle.Empty;

        /// <summary>
        /// Contains the destination rectangles used to draw the skin.
        /// </summary>
        protected Rectangle[] skinRects = new Rectangle[9];

        /// <summary>
        /// Indicates if the last time the control updated, the mouse was over it.
        /// </summary>
        protected bool lastMouseOverMe = false;

        /// <summary>
        /// Used to disable the resizing code.
        /// </summary>
        protected bool layoutSuspended = true;

        /// <summary>
        /// A name for the component so that It can be found by 
        /// name by the code using the GUI.
        /// </summary>
        protected string myName;

        /// <summary>
        /// Determines the order in which components are drawn. Lower values are 
        /// drawn before higher values.
        /// </summary>
        protected int DrawOrder = 0;

        /// <summary>
        /// The color used to draw the componet. Can be used to tint a skin, or
        /// make the control transparent by setting the alpha value of the color.
        /// </summary>
        protected Color myColor = Color.White;

        /// <summary>
        /// Determines if the control should be drawn or not. If visible is set to false,
        /// child components will also not be drawn.
        /// </summary>
        protected bool myVisible = true;

        protected string myCursor = "Default";

        // the component's postion and size relative to its parent.
        protected internal Rectangle myRectangle = Rectangle.Empty;
        // how far child components are pushed in from the edge.
        protected Rectangle myPadding = Rectangle.Empty;
        // the components position relative to the screen.
        // protected Rectangle myAbsoluteRectangle = Rectangle.Empty;
        // the components interior space relative to the screen.
        protected internal Rectangle myInterior = Rectangle.Empty;

        protected bool myInheritColor = true;
        protected bool myInheritFont = true;
        protected bool myInheritFontColor = true;

        #endregion

        // the serialized members region contains  all the public members that
        // can be serialized. To keep editing the XML files related to components
        // relatively simple, We start with the name as the very first element.
        // all other elements are in alphabetical order.
        #region SerializedMembers

        /// <summary>
        /// A name to identify the component for use by the code that
        /// utilizes the GUI.
        /// </summary>
        public string Name
        {
            get { return myName; }
            set { myName = value; }
        }

        [ContentSerializer(Optional = true)]
        public bool CanFocus
        {
            get { return myCanFocus; }
            set { myCanFocus = value; }
        }

        [ContentSerializer(Optional = true)]
        public List<Component> Children = new List<Component>();

        /// <summary>
        /// The color that will be used to draw the component. If the component is skinned,
        /// setting the color can tint the skin. Setting the Alpha value of the color will
        /// affect the transparency of the control. 
        /// </summary>
        [ContentSerializer(Optional = true)]
        public Color Color
        {
            get { return (myInheritFontColor && Parent != null) ? Parent.Color : myColor; }
            set { myColor = value; }
        }

        [ContentSerializer(Optional = true)]
        public string Cursor
        {
            get { return myCursor; }
            set { myCursor = value; }
        }

        [ContentSerializer(Optional = true)]
        public DockStyle Dock
        {
            get { return myDock; }
            set { myDock = value; }
        }

        [ContentSerializer(Optional = true)]
        public string Font
        {
            get { return (myInheritFont && Parent != null) ? Parent.Font : myFont; }
            set { myFont = value; }
        }

        [ContentSerializer(Optional = true)]
        public Color FontColor
        {
            get { return (myInheritFontColor && Parent != null) ? Parent.FontColor : myFontColor; }
            set { myFontColor = value; }
        }
        [ContentSerializer(Optional = true)]
        public bool InheritColor
        {
            get { return myInheritColor; }
            set { myInheritColor = value; }
        }
        [ContentSerializer(Optional = true)]
        public bool InheritFont
        {
            get { return myInheritFont; }
            set { myInheritFont = value; }
        }
        [ContentSerializer(Optional = true)]
        public bool InheritFontColor
        {
            get { return myInheritFontColor; }
            set { myInheritFontColor = value; }
        }

        [ContentSerializer(Optional = true)]
        public Rectangle Padding
        {
            get { return myPadding; }
            set { myPadding = value; UpdateRectangles(); }
        }

        public Rectangle Rectangle
        {
            get { return myRectangle; }
            set { myRectangle = value; UpdateRectangles(); }
        }

        [ContentSerializer(Optional = true)]
        public virtual string TabNext
        {
            get { return myTabNext; }
            set { myTabNext = value; }
        }

        [ContentSerializer(Optional = true)]
        public virtual string TabPrev
        {
            get { return myTabPrev; }
            set { myTabPrev = value; }
        }

        [ContentSerializer(Optional = true)]
        public virtual string Text
        {
            get { return myText; }
            set { SetText(value); }
        }

        protected virtual void SetText(string value)
        {
            if (myText != value)
            {
                myText = value;
                OnTextChanged();
            }
        }

        /// <summary>
        /// Determines if the component should be drawn. If Visible is false, the
        /// component and child components will not be drawn.
        /// </summary>
        [ContentSerializer(Optional = true)]
        public bool Visible
        {
            get { return myVisible; }
            set { myVisible = value; }
        }

        #endregion

        #region Non Serialized Properties
        //public Rectangle Absolute { get { return myAbsoluteRectangle; } }
        public virtual Rectangle Interior { get { return myInterior; } }
        #endregion


        #region Content Members
        /// <summary>
        /// Loads the componets settings from compiled content.
        /// </summary>
        /// <param name="input">a content reader currently reading a component.</param>
        protected virtual internal void ReadContent(ContentReader input)
        {
            // suspend the layout until we are done loading.
            // this prevents the resize code from running before all the 
            // size and location values are set.
            this.SuspendLayout();

            // Load all the properties of this component.
            this.Name = input.ReadString();
            this.Rectangle = input.ReadObject<Rectangle>();
            this.Padding = input.ReadObject<Rectangle>();
            this.Color = input.ReadColor();
            this.Visible = input.ReadBoolean();
            this.Cursor = input.ReadString();
            this.Text = input.ReadString();
            this.Font = input.ReadString();
            this.FontColor = input.ReadColor();
            this.Dock = (DockStyle)input.ReadInt32();
            this.InheritColor = input.ReadBoolean();
            this.InheritFont = input.ReadBoolean();
            this.InheritFontColor = input.ReadBoolean();
            this.myTabNext = input.ReadString();
            this.myTabPrev = input.ReadString();
            // load child components.
            this.Children = input.ReadObject<List<Component>>();

            // this will throw an exception if any of my children have the same name.
            this.CheckChildNames();

            // set the parent on child components.
            foreach (Component c in Children) { c.Parent = this; }

            // load any content required by this component.
            this.Load(input.ContentManager);
        }
        #endregion

        #region Rectangle Management

        //protected int AbsoluteY()
        //{ return  (Parent == null) ? myRectangle.Y : myRectangle.Y + Parent.AbsoluteY(); }

        //protected int AbsoluteX()
        //{ return (Parent == null) ? myRectangle.X : myRectangle.X + Parent.AbsoluteX(); }

        //protected void UpdateDock()
        //{
        //    Rectangle parentInterior;
        //    if (Parent != null)
        //    { parentInterior = Parent.Interior; }
        //    else
        //    {
        //        parentInterior = new Rectangle(0, 0,
        //            gui.GraphicsDevice.Viewport.Width,
        //            gui.GraphicsDevice.Viewport.Height);
        //    }

        //    switch (this.myDock)
        //    {
        //        case DockStyle.Top:
        //            this.myRectangle.X = 0;
        //            this.myRectangle.Y = 0;
        //            this.myRectangle.Width = parentInterior.Width;
        //            break;
        //        case DockStyle.Left:
        //            this.myRectangle.X = 0;
        //            this.myRectangle.Y = 0;
        //            this.myRectangle.Height = parentInterior.Height;
        //            break;
        //        case DockStyle.Bottom:
        //            this.myRectangle.X = 0;
        //            this.myRectangle.Y = parentInterior.Height - myRectangle.Height;
        //            this.myRectangle.Width = parentInterior.Width;
        //            break;
        //        case DockStyle.Right:
        //            this.myRectangle.X = parentInterior.Width - myRectangle.Width;
        //            this.myRectangle.Y = 0;
        //            this.myRectangle.Height = parentInterior.Height;
        //            break;
        //        case DockStyle.Fill:
        //            this.myRectangle = parentInterior;
        //            break;
        //        default:
        //            break;
        //    }
        //}

        protected virtual void UpdateRectangles()
        {
            // first get the dockspace left from the parent.
            if (Parent == null) return;

            Rectangle parentDock = this.Parent.myDockSpace;

            switch (myDock)
            {
                case DockStyle.Top:
                    myDrawRectangle.X = Parent.myDockSpace.X;
                    myDrawRectangle.Y = Parent.myDockSpace.Y;
                    myDrawRectangle.Width = Parent.myDockSpace.Width;
                    myDrawRectangle.Height = myRectangle.Height;
                    Parent.myDockSpace.Y += myRectangle.Height;
                    Parent.myDockSpace.Height -= myRectangle.Height;
                    break;
                case DockStyle.Bottom:
                    myDrawRectangle.X = Parent.myDockSpace.X;
                    myDrawRectangle.Y = Parent.myDockSpace.Y + Parent.myDockSpace.Height - myRectangle.Height;
                    myDrawRectangle.Width = Parent.myDockSpace.Width;
                    myDrawRectangle.Height = myRectangle.Height;
                    Parent.myDockSpace.Height -= myRectangle.Height;
                    break;
                case DockStyle.Left:
                    myDrawRectangle.X = Parent.myDockSpace.X;
                    myDrawRectangle.Y = Parent.myDockSpace.Y;
                    myDrawRectangle.Width = myRectangle.Width;
                    myDrawRectangle.Height = Parent.myDockSpace.Height;
                    Parent.myDockSpace.X += myRectangle.Width;
                    Parent.myDockSpace.Width -= myRectangle.Width;
                    break;
                case DockStyle.Right:
                    myDrawRectangle.X = Parent.myDockSpace.X + Parent.myDockSpace.Width - myRectangle.Width;
                    myDrawRectangle.Y = Parent.myDockSpace.Y;
                    myDrawRectangle.Width = myRectangle.Width;
                    myDrawRectangle.Height = Parent.myDockSpace.Height;
                    Parent.myDockSpace.Width -= myRectangle.Width;
                    break;
                case DockStyle.Fill:
                    myDrawRectangle = Parent.myDockSpace;
                    Parent.myDockSpace.Width = 0; // no space left.
                    Parent.myDockSpace.Height = 0; // no space left.
                    break;
                default:
                    // the componet should be drawn at its stated location.
                    myDrawRectangle.X = myRectangle.X + Parent.myDrawRectangle.X;
                    myDrawRectangle.Y = myRectangle.Y + Parent.myDrawRectangle.Y;
                    myDrawRectangle.Width = myRectangle.Width;
                    myDrawRectangle.Height = myRectangle.Height;
                    break;
            }

            // now update my dockspace.
            myDockSpace.X = myInterior.X = myDrawRectangle.X + myPadding.X;
            myDockSpace.Y = myInterior.Y = myDrawRectangle.Y + myPadding.Y;
            myDockSpace.Width = myInterior.Width = myDrawRectangle.Width - myPadding.X - myPadding.Width;
            myDockSpace.Height = myInterior.Height = myDrawRectangle.Height - myPadding.Y - myPadding.Height;
        }
        #endregion


        /// <summary>
        /// Provides the component and all its child components an opportunity to update.
        /// </summary>
        public virtual void Update(GameTime gameTime)
        {
            // not visible, nothing to do.
            if (!myVisible) return;

            bool mouseOver = this.IsMouseOver(gui.mouse.Location);

            if (mouseOver && !lastMouseOverMe)
            { DoMouseEnter(gui.mouse.getArgs()); OnMouseEnter(); }

            if (!mouseOver && lastMouseOverMe)
            { DoMouseExit(gui.mouse.getArgs()); OnMouseExit(); }

            UpdateComponents(gameTime);

            lastMouseOverMe = mouseOver;
        }

        /// <summary>
        /// Calls Update on all child components.
        /// </summary>
        protected virtual void UpdateComponents(GameTime gameTime)
        {
            // update all the child components.
            foreach (Component c in Children) { c.Update(gameTime); }
        }

        /// <summary>
        /// Checks to see if the mouse is over a child component.
        /// </summary>
        /// <returns>True if the mouse is over a child, otherwise false.</returns>
        protected internal bool IsMouseOverChild(Point p)
        {
            // the mouse can not be over a child component
            // if the parent is invisible.
            if (!myVisible) return false;

            // loop through each component.
            foreach (Component c in Children)
            //return true if the mouse is over that component.
            { if (c.IsMouseOver(p)) { return true; } }
            // if no child returned true, return false.
            return false;
        }

        /// <summary>
        /// Checks to see if the mous is over thi control.
        /// </summary>
        /// <returns>True if the mouse is over the control. False if it is not
        /// over this contorl, or it is over a child control.</returns>
        protected internal bool IsMouseOver(Point p)
        {
            // the mouse can not be over an invisible component.
            if (!myVisible) return false;

            // the mouse is not over this control if
            // it is over a child control.
            if (IsMouseOverChild(p)) { return false; }

            // check to see if the mouse is over this control.
            // notice that we use the absolute left and top. This
            // is because we want to know the controls screen position
            // because the mouse position is relative to the screen.
            return this.myDrawRectangle.Contains(p);
        }

        /// <summary>
        /// Changes the draw order so that this component is drawn last
        /// making it appear to be in front of overlapping components.
        /// </summary>
        public void BringToFront()
        {
            if (this.Parent != null)
            {
                Parent.NormalizeDrawOrder();
                this.DrawOrder = Parent.Children.Count;
            }
        }

        /// <summary>
        /// Changes the draw order so that this component is drawn first
        /// making it appear to be behind overlapping components.
        /// </summary>
        public void SendToBack()
        {
            if (this.Parent != null)
            {
                Parent.NormalizeDrawOrder();
                this.DrawOrder = 0;
            }
        }

        /// <summary>
        /// Sorts the components and renumbers their draw order to be sequential.
        /// </summary>
        protected void NormalizeDrawOrder()
        {
            Children.Sort();
            int i = 1;
            foreach (Component c in Children)
            {
                c.DrawOrder = i;
                i++;
            }
        }

        /// <summary>
        /// Stops this component and all child components from running
        /// any resizing code until ResumeLayout is called.
        /// </summary>
        public void SuspendLayout()
        {
            layoutSuspended = true;
            foreach (Component c in Children) { c.SuspendLayout(); }
        }

        /// <summary>
        /// Causes the componet and all child components to resume running
        /// resizing code.
        /// </summary>
        public void ResumeLayout()
        {
            layoutSuspended = false;
            foreach (Component c in Children) { c.ResumeLayout(); }
            Resize();
        }

        /// <summary>
        /// Draws the component on the screen. Also Draws all child components.
        /// </summary>
        public virtual void Draw()
        {
            if (!Visible) return;



            myGui.DrawRectangle(myDrawRectangle, this.myColor);
            DrawComponents();
        }

        /// <summary>
        /// Draws all child components on the screen.
        /// </summary>
        protected virtual void DrawComponents()
        {
            gui.batch.GraphicsDevice.ScissorRectangle = this.Interior;
            gui.batch.GraphicsDevice.RenderState.ScissorTestEnable = true;

            //Children.Sort();
            foreach (Component c in Children) { c.Draw(); }

            gui.batch.GraphicsDevice.RenderState.ScissorTestEnable = false;
        }

        /// <summary>
        /// updates the size of the component and all child components.
        /// </summary>
        public virtual void Resize()
        {
            if (layoutSuspended) return;
            UpdateRectangles();
            foreach (Component c in Children) { c.Resize(); }
            OnResize();
        }

        // this member must be called from the resize code
        // of a class that inherits component, but only
        // after base.Resize has been called.
        protected void UpdateSkinRects(ThemePart part)
        {
            int X1, X2, X3, Y1, Y2, Y3;
            int W1, W2, W3, H1, H2, H3;

            W1 = part.Rectangles["NW"].Width;
            W3 = part.Rectangles["NE"].Width;
            W2 = this.myDrawRectangle.Width - (W1 + W3);

            H1 = part.Rectangles["NW"].Height;
            H3 = part.Rectangles["SW"].Height;
            H2 = this.myDrawRectangle.Height - (H1 + H3);

            X1 = this.myDrawRectangle.X;
            X2 = X1 + W1;
            X3 = X2 + W2;

            Y1 = this.myDrawRectangle.Y;
            Y2 = Y1 + H1;
            Y3 = Y2 + H2;

            skinRects[0] = new Rectangle(X1, Y1, W1, H1);
            skinRects[1] = new Rectangle(X2, Y1, W2, H1);
            skinRects[2] = new Rectangle(X3, Y1, W3, H1);
            skinRects[3] = new Rectangle(X1, Y2, W1, H2);
            skinRects[4] = new Rectangle(X2, Y2, W2, H2);
            skinRects[5] = new Rectangle(X3, Y2, W3, H2);
            skinRects[6] = new Rectangle(X1, Y3, W1, H3);
            skinRects[7] = new Rectangle(X2, Y3, W2, H3);
            skinRects[8] = new Rectangle(X3, Y3, W3, H3);
        }

        // This region contains code that caused the event to 
        // be raised with the client code if an event handler 
        // has been assigned.
        #region Event Triggers

        protected internal void OnCreate()
        {
            foreach (Component c in Children)
            { c.OnCreate(); }
            myGui.OnComponentCreated(this);
        }

        protected virtual void OnMouseEnter()
        { if (MouseEnter != null) MouseEnter(this, myGui.mouse.getArgs()); }
        protected virtual void OnMouseExit()
        { if (MouseExit != null) MouseExit(this, myGui.mouse.getArgs()); }
        protected virtual void OnMouseClick()
        { if (MouseClick != null) MouseClick(this, myGui.mouse.getArgs()); }
        protected virtual void OnMouseClick(MouseEventArgs e)
        { if (MouseClick != null) MouseClick(this, e); }
        protected virtual void OnMouseDoubleClick()
        { if (MouseClick != null) MouseDoubleClick(this, myGui.mouse.getArgs()); }
        protected virtual void OnMouseDoubleClick(MouseEventArgs e)
        { if (MouseClick != null) MouseDoubleClick(this, e); }
        protected virtual void OnMouseUp()
        { if (MouseUp != null) MouseUp(this, myGui.mouse.getArgs()); }
        protected virtual void OnMouseDown()
        { if (MouseDown != null) MouseDown(this, myGui.mouse.getArgs()); }
        protected virtual void OnTextChanged()
        { if (this.TextChanged != null) TextChanged(this); }

        protected virtual void OnKeyUp(Keys k)
        { if (KeyUp != null) KeyUp(this, k); }
        protected virtual void OnKeyDown(Keys k)
        { if (KeyDown != null) KeyDown(this, k); }

        protected virtual void OnResize()
        { if (Resized != null) Resized(this); }
        protected virtual void OnEnter()
        { if (Enter != null) Enter(this); }
        protected virtual void OnLeave()
        { if (Leave != null) Leave(this); }


        #endregion

        public Component FindComponent(Point p)
        {
            foreach (Component c in Children)
            {
                if (c.IsMouseOver(p)) return c;
                if (c.IsMouseOverChild(p))
                {
                    return c.FindComponent(p);
                }
            }
            return null;
        }

        public Component FindComponent(string name)
        {
            if (name == null || name == string.Empty) return null;

            int i = name.IndexOf("\\");
            string firstPart, secondPart;
            if (i == -1)
            { firstPart = name; secondPart = ""; }
            else
            {
                firstPart = name.Substring(0, i);
                secondPart = name.Substring(i + 1);
            }

            foreach (Component c in Children)
            {
                if (firstPart == "..")
                {
                    if (secondPart == "")
                    { return Parent; }
                    else
                    { return Parent.FindComponent(secondPart); }
                }
                if (c.Name == firstPart)
                {
                    if (secondPart == "")
                    { return c; }
                    else
                    { return c.FindComponent(secondPart); }
                }
            }
            return null;
        }

        /// <summary>
        /// What component this component is a child of. May be null if
        /// the component is not a child.
        /// </summary>
        [ContentSerializerIgnore]
        public Component Parent;

        /// <summary>
        /// The GUI that this object is a part of.
        /// </summary>
        protected GUI myGui;
        /// <summary>
        /// Tracks the GUI object that owns the component. The component uses
        /// the gui to load its content and draw itself. 
        /// </summary>
        internal GUI gui
        {
            get { return myGui; }
            set
            {
                myGui = value;
                foreach (Component c in Children) { c.gui = value; }
            }
        }

        /// <summary>
        /// Used to load any conent need by the component.
        /// </summary>
        /// <param name="content">A ContentManager that can be used to load needed content.</param>
        public virtual void Load(ContentManager content) { }

        /// <summary>
        /// The screen area where the component will be drawn.
        /// </summary>
        protected internal Rectangle myDrawRectangle = Rectangle.Empty;

        /// <summary>
        /// The screen area where the component will be drawn.
        /// </summary>
        public Rectangle DrawRectangle
        { get { return myDrawRectangle; } }

        public void CheckChildNames()
        {
            List<string> names = new List<string>();
            foreach (Component c in Children)
            {
                if (names.Contains(c.Name))
                { throw new ApplicationException("'" + this.myName + "' has more than one child named '" + c.Name + "'."); }
                names.Add(c.Name);
            }

            foreach (Component c in Children) { c.CheckChildNames(); }
        }


        #region IComparable Implementation
        /// <summary>
        /// Used by IComparable so components can be sorted by draw order.
        /// </summary>
        /// <param name="other">the other component to compare against.</param>
        /// <returns>an indication of their relative draw orders.</returns>
        public int CompareTo(Component other)
        {
            return DrawOrder.CompareTo(other.DrawOrder);
        }

        public bool HasFocus()
        {
            return (this.myGui.HasFocus == this);
        }
        #endregion

        // these memebers are called by the internal mouse and keyboard 
        // events system. Components can override these to customize 
        // the response to the event. They can raise an event to the 
        // client code, react privately, muffle the event, pass
        // the event to their parent, or any combination of these.
        // The default action of the base component class is to 
        // pass the event to the parent.
        #region DoEvent Members
        public virtual void DoKeyDown(Keys k)
        {
            if (this.HasFocus())
            {
                if (k == Keys.Tab)
                { DoTabNext(); }
                else if (k == Keys.Tab && gui.keyboard.Shift)
                { DoTabPrev(); }
                else if (Parent != null)
                { Parent.DoKeyDown(k); }
            }
        }

        public virtual void DoKeyUp(Keys k)
        { if (Parent != null) Parent.DoKeyUp(k); }

        public virtual void DoMouseClick(MouseEventArgs e)
        { if (Parent != null) Parent.DoMouseClick(e); }

        public virtual void DoMouseDoubleClick(MouseEventArgs e)
        { if (Parent != null) Parent.DoMouseDoubleClick(e); }

        public virtual void DoMouseDown(MouseEventArgs e)
        { if (Parent != null) Parent.DoMouseDown(e); }

        public virtual void DoMouseUp(MouseEventArgs e)
        { if (Parent != null) Parent.DoMouseUp(e); }

        public virtual void DoMouseMove(MouseEventArgs e)
        { if (Parent != null) Parent.DoMouseMove(e); }

        public virtual void DoMouseEnter(MouseEventArgs e)
        { if (Parent != null) Parent.DoMouseEnter(e); }

        public virtual void DoMouseExit(MouseEventArgs e)
        { if (Parent != null) Parent.DoMouseExit(e); }

        public virtual void DoEnter()
        {
            if (this.CanFocus)
            { OnEnter(); }
            else if (Parent != null)
            { Parent.DoEnter(); }
        }

        public virtual void DoLeave()
        { if (this.HasFocus() && this.myCanFocus) OnLeave(); }

        public virtual void DoTabNext()
        {
            Component c = Parent.FindComponent(this.myTabNext);
            if (c != null) myGui.HasFocus = c;
        }

        public virtual void DoTabPrev()
        {
            Component c = Parent.FindComponent(this.myTabPrev);
            if (c != null) myGui.HasFocus = c;
        }

        public void TakeFocus()
        {
            myGui.HasFocus = this;
        }

        #endregion
    }
}
